#include "types.h"

#ifndef _ETH_H
#define _ETH_H

/*=========== states ========================*/
#define	STATUS_CLOSED		0
#define	STATUS_CLOSE		1
#define	STATUS_OPENED		2
#define STATUS_OPEN		3
#define STATUS_ABORT		4
#define STATUS_FIN		5

#define MTU_SIZE		(1500+ETH_HEADER_SIZE )

#define	MAX_TCP			5 /*max TCP entries*/

#define SWAP16(x)	swap16(x)
#define	SWAP32(x)	swap32(x)

/*========== types ===========================*/
typedef union
{
  byte	b8[6];
  UINT16 b16[3];
} MAC_addr;

typedef union
{
  byte		b8[4];
  UINT16	b16[2];
  UINT32	b32;
} IP_addr;

typedef struct
{
    MAC_addr	mac;
    IP_addr	ip;
    IP_addr	netmask;
    IP_addr	gateway;
} Device;

typedef struct
{
  MAC_addr	mac;
  IP_addr	ip;
  UINT16	port;
  UINT16	local_port;
  UINT32	acknum;
  UINT32	seqnum;
  
  byte		flags;
  byte		status;
  byte		time;
  byte		error;
} TCP_table;

/*----------- Ethernet */
#define ETH_OFFSET		0x00
#define ETH_HEADER_SIZE		0xE	/*15*/
#define ETH_TYPE_IP		SWAP16(0x0800)
#define ETH_TYPE_IPs	0x0080
#define	ETH_TYPE_ARP	SWAP16(0x0806)
#define ETH_TYPE_ARPs	0x0608
typedef struct
{
    MAC_addr	dst_mac;
    MAC_addr	src_mac;
    UINT16	type;		/* IPv4 = 0800, ARP= 0806*/
} ETH_Header;

/*----------- ARP */
#define	ARP_OFFSET		0x0E
#define	ARP_HEADER_SIZE		0x1C /*28*/
#define ARP_REQUEST		0x01
#define ARP_REPLY		0x02
typedef struct
{
    UINT16	hw_type;	/* hardware type*/
    UINT16	protocol_type;	
    byte	hw_len;		/* hardware address len*/
    byte	protocol_len;
    UINT16	op;		/*operation*/
    MAC_addr	src_mac;
    IP_addr	src_ip;
    MAC_addr	dst_mac;
    IP_addr	dst_ip;
} ARP_Header;

/*------------ IP*/
#define IP_OFFSET		0x0E
#define IP_HEADER_SIZE		0x14 /*20*/
#define IP_PROTO_ICMP		0x01
#define IP_PROTO_TCP		0x06
#define IP_PROTO_UDP		0x11
typedef struct
{
    byte	ver_len;	/*4b version, 4b header len*/
    byte	tos;		/*type of service*/
    UINT16	len;		/*packet length*/
    UINT16	id;		/*id*/
    UINT16	flag_offs;	/*3b flags, 13b offset */
    byte	ttl;		/*time-to-live*/
    byte	proto;		/*protocol*/
    UINT16	checksum;	/* checksum of IP header*/
    IP_addr	src_ip;
    IP_addr	dst_ip;
} IP_Header;

/*--------------- ICMP*/
#define ICMP_OFFSET		0x22
#define	ICMP_HEADER_SIZE	0x04
#define	ICMP_ECHO_REP		0x00
#define ICMP_ECHO_REQ		0x0800
typedef struct
{
    byte	type;		/* type, 0- echo reply, 8- echo request*/
    byte	code;		/* code*/
    UINT16	checksum;	
    byte	data;		/*start of data*/
} ICMP_Header;

/*--------------- TCP*/
#define TCP_OFFSET		0x22
#define TCP_HEADER_SIZE		0x14 /*20*/
#define TCP_DATA_START		(ETH_HEADER_SIZE+TCP_HEADER_SIZE+IP_HEADER_SIZE)
#define TCP_MSS			(MTU_SIZE - ETH_HEADER_SIZE - IP_HEADER_SIZE - TCP_HEADER_SIZE )
#define TCP_TIMEOUT		0x3
#define TCP_MAX_ERROR		0x3
#define TCP_FLAG_FIN		0x01
#define TCP_FLAG_SYN		0x02
#define TCP_FLAG_RST		0x04
#define TCP_FLAG_PSH		0x08
#define TCP_FLAG_ACK		0x10
typedef struct
{
    UINT16	src_port;
    UINT16	dst_port;
    UINT32	seq_num;
    UINT32	ack_num;
    byte	len;		/*4b header len in 32b steps*/
	byte	reserved;
    byte	flags;
    UINT16	window;
    UINT16	checksum;
    UINT16	urgent_pointer;
    byte	options[44];
} TCP_Header;

/*-------------------------- UDP */
#define UDP_OFFSET		0x22
#define UDP_HEADER_SIZE	0x08
#define UDP_DATA		(ETH_HEADER_SIZE+UDP_HEADER_SIZE+IP_HEADER_SIZE)
#define UDP_PORT		(7621)
typedef struct
{
	UINT16	src_port;
	UINT16	dst_port;
	UINT16	len;
	UINT16	checksum;
} UDP_Header;



/*================= prototypes =======================================*/
void	TCP_Abort( byte index );
void	TCP_Close( byte index );
byte	TCP_Open( MAC_addr *dst_mac, IP_addr *dst_ip, UINT16 dst_port, UINT16 src_port);
void	TCP_Send( byte index, UINT16 len, byte options);
void	TCP_Service( void );

void	ICMP_Service( void );

void	ARP_Request( IP_addr *ip);
MAC_addr* ARP_GetMac( IP_addr *ip);
void	ARP_service( void );

void	UDP_Service( void );

UINT16	checksumTCP( byte *s, UINT16 len, IP_addr *dst_ip );
UINT16	checksum( byte *s, UINT16 len );
void	Make_TCP_Header( byte index, UINT16 len, byte options );
void	Make_IP_Header( MAC_addr* dst_mac, IP_addr* dst_ip, UINT16 len, UINT16 proto );
void	Make_UDP_Header( MAC_addr* dst_mac, IP_addr* dst_ip, UINT16 dst_port, UINT16 len );
void	Make_ARP_Header( MAC_addr* dst_mac, MAC_addr* dst_arp_mac, IP_addr* dst_arp_ip, UINT16 op);
void	Make_ETH_Header( MAC_addr* dst_mac);

void	ETH_TimeService( void );
void	ETH_Service( void );
void	ETH_SetGateway( IP_addr* gateway );
void	ETH_SetNetmask( IP_addr* netmask );
void	ETH_SetIp( IP_addr *ip);
void	ETH_SetMac( MAC_addr* mac);
void	ETH_Init( void );

UINT16	swap16( UINT16 i );
UINT32	swap32( UINT32 i );

#endif